// TinyMCE 与 AngularJS 1.x 的适配指令：
// - 负责初始化编辑器、同步 ngModel、处理只读配置
// - 结合 image-preview-controller 实现富文本图片双击预览
import angular from 'angular';
import ngTinymceTemplate from './ng-tinymce.template.html';
import tinymce from './tinymce-loader';
import createImagePreviewController from './image-preview-controller';

// 内置的只读态工具栏配置：仅保留预览/全屏，方便在禁用态仍能操作
const DEFAULT_READONLY_VISUAL_CONFIG = {
  menubar: false,
  toolbar: 'preview fullscreen',
  plugins: 'fullscreen preview',
  toolbar_sticky: false
};

// 只读行为选项：是否保留工具栏等（例如禁用态仍可使用预览按钮）
const DEFAULT_READONLY_BEHAVIOR = {
  preserveToolbar: true
};

function ensureTinymce($window, $q) {
  if ($window && !$window.tinymce) {
    $window.tinymce = tinymce;
  }

  return $q.when($window ? $window.tinymce : tinymce);
}

// TinyMCE 默认配置（可通过 scope.config 定制）
const DEFAULT_EDITOR_CONFIG = {
  menubar: false,
  branding: false,
  height: 320,
  plugins: 'lists link image table code fullscreen',
  toolbar:
    'undo redo | formatselect | bold italic underline forecolor | alignleft aligncenter alignright alignjustify | bullist numlist | table | link image | removeformat | code fullscreen',
  convert_urls: false
};

ngTinymceDirective.$inject = ['$window', '$document', '$timeout', '$q'];

export default function ngTinymceDirective($window, $document, $timeout, $q) {
  return {
    restrict: 'E',
    template: ngTinymceTemplate,
    scope: {
      ngModel: '=',
      config: '=?',
      placeholder: '@?',
      disabled: '=?',
      readonlyConfig: '=?',
      onInit: '&?',
      imagePreviewEnabled: '=?'
    },
    link: function(scope, element) {
      const textarea = element[0].querySelector('textarea');
      let editor = null;
      let settingContent = false;
      // 记录当前只读配置，用于动态切换
      let currentReadonlySettings = null;
      let currentReadonlyBehavior = null;
      // 图片预览相关：只负责 TinyMCE 文档中的双击绑定，具体预览行为交给控制器
      let imagePreviewDetach = null;
      const previewController = createImagePreviewController($window, $document);

      function hasReadonlyOverrides() {
        return (
          scope.readonlyConfig !== undefined &&
          scope.readonlyConfig !== null &&
          scope.readonlyConfig !== false
        );
      }

      function detachPreviewDragListeners() {
        $document.off('mousemove', handlePreviewPointerMove);
        $document.off('touchmove', handlePreviewPointerMove);
        $document.off('mouseup', handlePreviewPointerUp);
        $document.off('touchend', handlePreviewPointerUp);
        $document.off('touchcancel', handlePreviewPointerUp);
      }

      function getPointerPosition(event) {
        if (event.touches && event.touches.length) {
          const touch = event.touches[0];
          return {
            x: touch.clientX,
            y: touch.clientY
          };
        }

        return {
          x: event.clientX,
          y: event.clientY
        };
      }

      function isPreviewDraggable() {
        return previewZoom > 1;
      }

      function setPreviewDraggingCursor(active) {
        if (!previewImageElement) {
          return;
        }

        if (!isPreviewDraggable()) {
          previewImageElement.style.cursor = previewZoom > 1 ? 'grab' : 'default';
          return;
        }

        previewImageElement.style.cursor = active ? 'grabbing' : 'grab';
      }

      function handlePreviewPointerDown(event) {
        if (!isPreviewDraggable()) {
          return;
        }

        event.preventDefault();

        previewDragActive = true;
        previewDragStartPoint = getPointerPosition(event);
        previewDragOrigin = { x: previewPosition.x, y: previewPosition.y };
        // 当前版本不做位置惯性，仅在拖动结束时回弹到可视区域
        setPreviewDraggingCursor(true);

        $document.on('mousemove', handlePreviewPointerMove);
        $document.on('touchmove', handlePreviewPointerMove);
        $document.on('mouseup', handlePreviewPointerUp);
        $document.on('touchend', handlePreviewPointerUp);
        $document.on('touchcancel', handlePreviewPointerUp);
      }

      function handlePreviewPointerMove(event) {
        if (!previewDragActive) {
          return;
        }

        event.preventDefault();

        const point = getPointerPosition(event);
        const delta = {
          x: point.x - previewDragStartPoint.x,
          y: point.y - previewDragStartPoint.y
        };

        previewPosition = {
          x: previewDragOrigin.x + delta.x,
          y: previewDragOrigin.y + delta.y
        };

        // 拖动过程中仅更新位置，不做边界修正，避免卡顿
        renderPreviewTransform();
      }

      function handlePreviewPointerUp() {
        if (!previewDragActive) {
          return;
        }

        previewDragActive = false;
        setPreviewDraggingCursor(false);
        detachPreviewDragListeners();
        // 拖动结束后再做一次边界修正，让图片平滑回到可视区域
        applyPreviewTransform({ ensureBounds: true });
      }

      function resolveReadonlySettings(disabled) {
        if (!disabled || !hasReadonlyOverrides()) {
          return null;
        }

        if (scope.readonlyConfig === true) {
          return {
            config: angular.copy(DEFAULT_READONLY_VISUAL_CONFIG),
            behavior: angular.copy(DEFAULT_READONLY_BEHAVIOR)
          };
        }

        if (angular.isObject(scope.readonlyConfig)) {
          const overrides = angular.copy(scope.readonlyConfig);
          const behavior = angular.extend({}, DEFAULT_READONLY_BEHAVIOR);

          if (overrides.preserveToolbar !== undefined) {
            behavior.preserveToolbar = !!overrides.preserveToolbar;
            delete overrides.preserveToolbar;
          }

          return {
            config: overrides,
            behavior: behavior
          };
        }

        return null;
      }

      function refreshReadonlySettings(disabled) {
        currentReadonlySettings = resolveReadonlySettings(disabled);
        currentReadonlyBehavior = currentReadonlySettings ? currentReadonlySettings.behavior : null;
      }

      // 已移至 image-preview-controller 中

      function detachImagePreviewListener() {
        if (imagePreviewDetach) {
          imagePreviewDetach();
          imagePreviewDetach = null;
        }
      }

      function updateImagePreviewBinding() {
        detachImagePreviewListener();

        if (!editor || !isImagePreviewEnabled()) {
          return;
        }

        const doc = editor.getDoc();

        if (!doc) {
          return;
        }

        const handler = function(event) {
          const target = event.target;

          if (!target || target.nodeName !== 'IMG') {
            return;
          }

          const rawSrc = target.getAttribute('src');
          if (!rawSrc) {
            return;
          }

          event.preventDefault();
          event.stopPropagation();

          const previewSrc =
            target.getAttribute('data-preview-src') ||
            target.getAttribute('preview-src') ||
            target.getAttribute('data-large-src') ||
            rawSrc;

          const caption =
            target.getAttribute('data-preview-title') ||
            target.getAttribute('preview-title') ||
            target.getAttribute('title') ||
            target.getAttribute('alt') ||
            '';

          previewController.show(previewSrc, caption);
        };

        doc.addEventListener('dblclick', handler, true);

        imagePreviewDetach = function() {
          doc.removeEventListener('dblclick', handler, true);
        };
      }

      function destroyEditor() {
        detachImagePreviewListener();

        if (editor && $window.tinymce) {
          $window.tinymce.remove(editor);
        }

        editor = null;
      }

      function syncEditorContent(value) {
        if (!editor) {
          return;
        }

        const safeValue = value || '';
        const currentValue = editor.getContent({ format: 'raw' }) || '';

        if (safeValue === currentValue) {
          return;
        }

        editor.setContent(safeValue);
      }

      function updateReadonlyState(disabled) {
        if (!editor) {
          return;
        }

        const behavior = disabled ? currentReadonlyBehavior : null;
        const preserveToolbar = !!(behavior && behavior.preserveToolbar);
        const desiredMode = disabled && !preserveToolbar ? 'readonly' : 'design';

        if (editor.mode && angular.isFunction(editor.mode.set)) {
          editor.mode.set(desiredMode);
        } else if (angular.isFunction(editor.setMode)) {
          editor.setMode(desiredMode);
        }

        var body = editor.getBody();
        if (body) {
          body.setAttribute('contenteditable', preserveToolbar ? 'false' : disabled ? 'false' : 'true');
          if (preserveToolbar) {
            body.classList.add('ng-tinymce-readonly');
          } else {
            body.classList.remove('ng-tinymce-readonly');
          }
        }
      }

      function handleEditorChange() {
        if (!editor) {
          return;
        }

        const content = editor.getContent({ format: 'raw' }) || '';

        settingContent = true;
        scope.$applyAsync(function() {
          scope.ngModel = content;
          settingContent = false;
        });
      }

      function initEditor() {
        ensureTinymce($window, $q)
          .then(function(tinymce) {
            destroyEditor();

            const userConfig = scope.config || {};
            const userSetup = userConfig.setup;
            refreshReadonlySettings(scope.disabled);
            const readonlySettings = currentReadonlySettings;
            const behavior = currentReadonlyBehavior;
            const shouldUseNativeReadonly = scope.disabled && !(behavior && behavior.preserveToolbar);

            let editorConfig = angular.extend({}, DEFAULT_EDITOR_CONFIG, userConfig, {
              target: textarea,
              readonly: shouldUseNativeReadonly ? scope.disabled : false
            });

            if (readonlySettings && readonlySettings.config) {
              editorConfig = angular.extend({}, editorConfig, readonlySettings.config);
            }

            if (
              editorConfig.skin === undefined &&
              editorConfig.skin_url === undefined
            ) {
              editorConfig.skin = false;
            }

            if (editorConfig.content_css === undefined) {
              editorConfig.content_css = false;
            }

            editorConfig.setup = function(instance) {
              editor = instance;

              instance.on('init', function() {
                syncEditorContent(scope.ngModel);
                updateReadonlyState(scope.disabled);

                if (angular.isFunction(scope.onInit)) {
                  scope.onInit({ $editor: instance });
                }

                updateImagePreviewBinding();
              });

              const changeEvents = 'change keyup undo redo input';
              changeEvents.split(' ').forEach(function(eventName) {
                instance.on(eventName, handleEditorChange);
              });

              instance.on('blur', handleEditorChange);

              if (angular.isFunction(userSetup)) {
                userSetup(instance);
              }
            };

            tinymce.init(editorConfig);
          })
          .catch(function(error) {
            console.error('[ngTinymce] Failed to initialize TinyMCE:', error);
          });
      }

      let hasConfigWatcherFired = false;

      scope.$watch(
        function() {
          return scope.config;
        },
        function(newValue, oldValue) {
          if (!hasConfigWatcherFired) {
            hasConfigWatcherFired = true;
            return;
          }

          if (angular.equals(newValue, oldValue)) {
            return;
          }

          initEditor();
        },
        true
      );

      scope.$watch(
        function() {
          return scope.ngModel;
        },
        function(newValue) {
          if (!editor || settingContent) {
            return;
          }

          syncEditorContent(newValue);
        }
      );

      let disabledWatcherInitialized = false;
      scope.$watch(
        function() {
          return scope.disabled;
        },
        function(newValue, oldValue) {
          if (!disabledWatcherInitialized) {
            disabledWatcherInitialized = true;
            updateReadonlyState(newValue);
            return;
          }

          if (newValue === oldValue) {
            return;
          }

          if (hasReadonlyOverrides()) {
            initEditor();
            return;
          }

          refreshReadonlySettings(newValue);
          updateReadonlyState(newValue);
        }
      );

      let readonlyConfigWatcherInitialized = false;
      scope.$watch(
        function() {
          return scope.readonlyConfig;
        },
        function(newValue, oldValue) {
          if (!readonlyConfigWatcherInitialized) {
            readonlyConfigWatcherInitialized = true;
            return;
          }

          if (angular.equals(newValue, oldValue)) {
            return;
          }

          if (scope.disabled) {
            initEditor();
          }
        },
        true
      );

      let imagePreviewWatcherInitialized = false;
      scope.$watch(
        function() {
          return scope.imagePreviewEnabled;
        },
        function(newValue, oldValue) {
          if (!imagePreviewWatcherInitialized) {
            imagePreviewWatcherInitialized = true;
            if (newValue === undefined) {
              scope.imagePreviewEnabled = false;
              return;
            }
          }

          if (newValue === oldValue) {
            return;
          }

          updateImagePreviewBinding();
        }
      );

      initEditor();

      scope.$on('$destroy', function() {
        destroyEditor();
        previewController.destroy();
      });
    }
  };
}
